package interactions;

import java.awt.Point;
import java.util.HashMap;
import java.util.Map;

import sprite.Sprite;
import spritebehavior.Behavior;



/**
 * Concrete strategy for collisions.
 * 
 * @author Seon Kang
 * @author Yaqi Zhang
 * @author Guy Tracy
 */

public class CollisionInteraction implements Interaction {
    private HashMap<SpritesTypePair, Reaction> myReactMap;

    /**
     * This class detects whether two sprites collide and responds differently
     * to different interacting sprites according to the mapping between
     * SpritesTypePair and corresponding reactions.
     * 
     * The sprite type is defined by the behavior it has because there is only
     * one kind of Sprite object, i.e. this is really a mapping between a pair
     * of Strategies and the reaction of the sprites that applying these
     * strategies.
     */
    public CollisionInteraction () {
        myReactMap = new HashMap<SpritesTypePair, Reaction>();
        // These should be register at somewhere else later;
        // registerReactions(crazyBehavior.getClass(),dumbBehavior.getClass(),SwapVelocity)
    }

    /**
     * Get the Reaction between sprite 1 and sprite 2 after collision from the
     * map and call Reaction to do something on sprite 1 and sprite 2.
     * 
     * @param sp1 sprite 1
     * @param sp2 sprite 2
     */
    @Override
    public void doStrategyAction (Sprite sp1, Sprite sp2) {
        Reaction react = getReaction(sp1, sp2);
        react.doStrategyAction(sp1, sp2);
    }

    /**
     * Add the mapping between reactions and two sprites that are interacting.
     * 
     * @param stp SpritesTypePair is the pair of Sprites that interact with each
     *        other.
     * @param react is the reaction between these two type of Sprites.
     */
    public void registerReactions (SpritesTypePair stp, Reaction react) {
        myReactMap.put(stp, react);
    }

    /**
     * Add the mapping between reactions and two sprites that are interacting.
     * 
     * @param sp1Type is the behavior type of sprite 1
     * @param sp2Type is the behavior type of sprite 2
     * @param react is the reaction between these two type of Sprites.
     */
    public void registerReactions (Class<? extends Behavior> sp1Type,
            Class<? extends Behavior> sp2Type, Reaction react) {
        registerReactions(new SpritesTypePair(sp1Type, sp2Type), react);
    }

    /**
     * Add the mapping between reactions and two sprites that are interacting.
     * 
     * @param sp1 is the sprite 1
     * @param sp2 is the sprite 2
     * @param react is the reaction between these two type of Sprites.
     */
    public void registerReactions (Sprite sp1, Sprite sp2, Reaction react) {
        SpritesTypePair stp = new SpritesTypePair(sp1, sp2);
        registerReactions(stp, react);
    }

    private Reaction getReaction (Sprite sp1, Sprite sp2) {
        return getReaction(new SpritesTypePair(sp1, sp2));
    }

    private Reaction getReaction (SpritesTypePair stp) {
        return myReactMap.get(stp);
    }

    /**
     * Checks to see if s1 and s2 are colliding.
     * 
     * @param s1 sprite 1
     * @param s2 sprite 2
     */
    @Override
    public boolean isInteracting (Sprite s1, Sprite s2) {
        int halfWidth = s2.getSize().width / 2;
        int halfHeight = s2.getSize().height / 2;
        Point topLeft = new Point(s2.getCenter().x - halfWidth,
                s2.getCenter().y - halfHeight);
        Point topRight = new Point(s2.getCenter().x + halfWidth,
                s2.getCenter().y - halfHeight);
        Point bottomLeft = new Point(s2.getCenter().x - halfWidth,
                s2.getCenter().y + halfHeight);
        Point bottomRight = new Point(s2.getCenter().x + halfWidth,
                s2.getCenter().y + halfHeight);
        if (s1.intersects(topLeft) || s1.intersects(topRight) ||
                s1.intersects(bottomLeft) || s1.intersects(bottomRight)) { return true; }
        return false;
    }
    
    /** 
     * populates reactionMap.
     * 
     * @param reactionMap
     */
    @Override
    public void registerMultipleReactions(Map<SpritesTypePair,Reaction> reactionMap) {
        myReactMap.putAll(reactionMap);
    }
}
